package com.hzw.saas.web.app.workspace.controller;

import java.util.Optional;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.hzw.saas.api.user.IUserRightsService;
import com.hzw.saas.api.user.bo.UserRightsBO;
import com.hzw.saas.api.workspace.IWorkInstanceService;
import com.hzw.saas.api.workspace.bo.WorkInstanceBo;
import com.hzw.saas.api.workspace.bo.WorkInstanceInfoBo;
import com.hzw.saas.common.config.annotation.SysLog;
import com.hzw.saas.common.config.aspect.RedisLockAspect;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.security.pojo.dto.SaasUser;
import com.hzw.saas.common.security.utils.SecurityUtils;
import com.hzw.saas.common.util.UnitConvertUtils;
import com.hzw.saas.common.util.enums.TimeUnitEnum;
import com.hzw.saas.web.app.workspace.annotation.WorkspaceOperation;
import com.hzw.saas.web.app.workspace.dto.InstCreateDto;
import cn.hutool.core.text.StrFormatter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 工作实例控制与连接
 * </p>
 *
 * @author sonam
 * @since 2021/2/4 14:10
 */
@Api(tags = "云控制台/工作实例")
@Slf4j
@RequestMapping("/workInstance")
@RestController
@RequiredArgsConstructor
public class WorkInstanceController {

    private final IWorkInstanceService workInstanceService;
    private final IUserRightsService userRightsService;
    private final RedissonClient redissonClient;

    @PostMapping("/register/{productId}")
    @SysLog(operation = "开通/开启产品在线使用", mode = 3)
    @ApiOperation(value = "开启产品在线使用", notes = "使用产品ID注册对应的工作实例，注册后可在实例列表中查询到")
    @ApiOperationSort(0)
    @ApiResponses({
        @ApiResponse(code = 200, message = "开启成功"),
        @ApiResponse(code = 202, message = "重复开启")
    })
    public ResponseEntity<InstCreateDto> register(@ApiParam("产品ID") @PathVariable String productId) {
        SaasUser user = SecurityUtils.getUser();

        RLock lock = redissonClient.getLock(StrFormatter.format("{}CreateWorkInstance:{}:{}", RedisLockAspect.REDISSON_LOCK_PREFIX, user.getUserId(), productId));
        AssertUtil.assertThrow("正在开启产品实例", HttpStatus.ACCEPTED, lock.isLocked());

        WorkInstanceBo workInstance = workInstanceService.createWorkInstance(user.getUserId(), productId, false);
        return ResponseEntity.ok(new InstCreateDto(workInstance.getInstId()));
    }

    @GetMapping("/{instId}/expire")
    @SysLog
    @ApiOperation(value = "获取实例过期时间", notes = "获取工作实例过期时间，单位：秒")
    public ResponseEntity<Long> getExpireTime(@PathVariable String instId) {
        long workInstanceExpire = workInstanceService.getWorkInstanceExpire(instId);
        return ResponseEntity.ok(workInstanceExpire);
    }

    @PutMapping("/{instId}/expire")
    @SysLog(operation = "续期实例", mode = 3)
    @ApiOperation(value = "续期实例", notes = "续期实例的运行时间")
    public ResponseEntity<String> addExpireTime(@PathVariable String instId) {
        SaasUser user = SecurityUtils.getUser();
        Optional<UserRightsBO> userRights = Optional.ofNullable(userRightsService.getUserRightsByUser(user.getUserId()));
        String recycleDuration = userRights.map(UserRightsBO::getDockerRecycleDuration).orElse("");
        long recycleSeconds = UnitConvertUtils.convertDatetime(recycleDuration, TimeUnitEnum.SECOND).longValue();
        workInstanceService.setWorkInstanceExpire(instId, recycleSeconds);
        return ResponseEntity.ok("实例续期成功");
    }

    @GetMapping("/list")
    @SysLog
    @ApiOperation(value = "分页获取用户实例", notes = "获取当前用户的工作实例，注：每个实例的状态要通过接口‘查看工作实例’获取")
    @ApiOperationSort(1)
    public ResponseEntity<IPage<WorkInstanceBo>> getAllWorkInstance(PageParam pageParam) {
        String userId = SecurityUtils.getUser().getUserId();
        return ResponseEntity.ok(workInstanceService.getAllWorkInstance(pageParam, userId));
    }

    @Deprecated
    @WorkspaceOperation(instId = "#instId")
    @SysLog(operation = "开启工作实例", mode = 3)
    @PostMapping("/start/{instId}")
    @ApiOperation(value = "开启工作实例", notes = "传入instId申请启动一个工作实例，返回成功表示申请成功。" +
        "注：返回成功后还需要使用接口‘查看工作实例’获取实例的运行状态和访问地址等信息")
    @ApiOperationSort(2)
    public ResponseEntity<String> startWorkInstance(@ApiParam("工作实例ID") @PathVariable String instId) {
//        workInstanceService.startWorkInstance(instId);
        return ResponseEntity.ok("开启工作实例成功");
    }

    @PostMapping("/run/count")
    @SysLog
    @ApiOperation(value = "获取工作实例的数量", notes = "获取工作实例的数量")
    @ApiOperationSort(3)
    public ResponseEntity<Integer> startWorkInstance() {
        return ResponseEntity.ok(workInstanceService.getWorkInstanceRunCount(SecurityUtils.getUser().getUserId()));
    }

    @WorkspaceOperation(instId = "#instId")
    @SysLog(operation = "停止工作实例（关机）", mode = 3)
    @PostMapping("/stop/{instId}")
    @ApiOperation(value = "停止工作实例（关机）", notes = "停止工作实例后，可使用该instId调用接口‘开启工作实例’再次启动")
    @ApiOperationSort(4)
    public ResponseEntity<String> stopWorkInstance(@ApiParam("工作实例ID") @PathVariable String instId) {
        workInstanceService.stopWorkInstance(instId);
        return ResponseEntity.ok("停止工作实例成功");
    }

    @WorkspaceOperation(instId = "#instId")
    @SysLog(operation = "删除一个工作实例（关机并删除）", mode = 3)
    @DeleteMapping("/{instId}")
    @ApiOperation(value = "删除一个工作实例（关机并删除）", notes = "删除工作实例相当于彻底销毁该实例, 无法再用instId启动。销毁后工作空间文件会继续保留一段时间")
    @ApiOperationSort(5)
    public ResponseEntity<String> deleteWorkInstance(@ApiParam("工作实例ID") @PathVariable String instId) {
        workInstanceService.deleteWorkInstance(instId);
        return ResponseEntity.ok("删除实例成功");
    }

    @WorkspaceOperation(instId = "#instId")
    @SysLog
    @GetMapping("/{instId}")
    @ApiOperation(value = "查看工作实例", notes = "获取工作实例的详细信息，例如运行状态和访问地址等信息")
    @ApiOperationSort(6)
    public ResponseEntity<WorkInstanceInfoBo> selectWorkInstance(@ApiParam("工作实例ID") @PathVariable String instId) {
        return ResponseEntity.ok(workInstanceService.selectWorkInstance(instId));
    }


}
